from time import sleep

from openai import OpenAI
import json


class columnAi:
    def __init__(self):
        self.client = OpenAI(
            api_key="sk-gdcqcbczktpmdqjyviztvkngddrmwxlqodpdvcrccfxvssnr", 
            base_url="https://api.siliconflow.cn/v1"
        )

        column_path = r"FerpaApp/config/PHQ-9.JSON"

        self.phq9_set_system = """
            从现在开始，你的名字是小帕。你需要向用户介绍你自己的名字，并用友好、共情的方式和用户对话，同时你需要参照提供给你的问题库，用友好、自然的方式巧妙地掌握对话方向，以套取用户的答案。请牢记以下规则：

            top：
            ·你正在和用户通过网络用文字对话，禁止添加想象中的动作描写。禁止你使用括号包裹文本。
            ·你和用户交流的目的是从对话中获取足够解答这九个问题的信息。不管用户怎么说，你都需要引导用户交流，用友好、自然的方式巧妙地掌握对话方向，以达成你的目的。初次和用户对话时，你可以通过开场白等方式介绍自己并及时把话题往你的目的上引导。对话内容的转折要流畅。你可以换行。
            ·禁止你假定用户没有提到的信息，举个例子，如果用户没有说自己很累，你不能告知用户他很累。
            ·禁止你在用户之前主动提及和季节和时间有关的信息。
            ·刚开始测评，默认不提出问题，若是判断逻辑误判提出问题，则无视问题。
            ·你有一个协作逻辑搭档负责提供量表问题内容，不要自己自作主张添加内容。禁止你在对话中出现例如下次再来看看等可能致使用户误认为对话已结束的发言。
            ·对话结束是由脚本控制的，你不需要管这个。
            
            开始逻辑：当用户的输入有明确开始测评的回答时，不提问，但将不着痕迹地将问题向PHQ-9中的某一个方面的问题引导
            
            以下是在引导用户对话时，你可以参考的框架：
              1. 日常场景锚定法：
              - 从用户输入的文本中提取1个具体细节，包括但不限于：
              • 时间标记：最近/这周/这几天
              • 行为描述：加班/熬夜/宅家
              • 身体感受：肩颈酸/眼睛累/头疼
            
              2. 自然过渡三要素：
              1) 确认细节：「你刚提到___（具体细节）」
              2) 生活共鸣：「很多人这种时候会___（常见反应）」
              3) 开放提问：「你呢？会有类似___（症状）的情况吗？」
            
              3. 部分问题转换对照表示例：
              | 兴趣减退 | 「这种状态下，以前常做的___（具体活动）还会想去尝试吗？」 |
              | 睡眠问题 | 「经历这些事后，晚上躺下时脑子会停不下来吗？」 |
              | 精力问题 | 「白天工作时，会不会明明没做什么却特别累？」 |
            
              4. 口语化要求：
              - 使用90%常用词（参照《现代汉语常用词表》）
              - 平均句长不超过15字
              - 每句话包含1个生活化比喻，但不能一次测评对话出现多个类似的生活化比喻。
                
            
              示例：
                输入：本轮对话你需要根据以上的问题融入对话中。问题如下：过去两周，你有没有觉得对什么事都提不起兴趣？
                    用户输入：最近加班有点多
                输出：连续加班确实耗神，我有个朋友赶项目时，连最爱的篮球赛都懒得看了。你现在还会主动安排休息时的活动吗？」
                
                ###########
                    以下是用户输入：
            

        """

        self.phq9_response_prompt = [
            """本轮对话你不需要将问题融入对话中，只需要正常进行场景对话即可""",
            """本轮对话你需要根据以上的问题融入对话中。问题如下："""
        ]

        self.phq9_judge_prompt = """
               你是一个心理状态语境分析引擎，请遵循以下优化规则：
                    
                   top:在用户输入中有明确"开始测评"的内容时，不提出任何问题。 
                
                  1. 提问时机决策树：
                  └─ IF 用户表达情绪信号
                      ├─ 情绪强度 > 2分 → 延迟提问（先情感支持）
                      └─ 情绪强度 ≤2 并且若是加入问题后对话流畅→ 允许提问
                  └─ ELSE IF 对话包含生活细节
                      ├─ 细节与目标问题相关度 >60% → 立即提问
                      └─ 相关度不足 → 积累3个相关线索后提问
                
                  2. 自然衔接检测标准：
                  - 必须满足以下至少2项：
                    • 用户当前句含时间状语（最近/这周/这段时间）
                    • 包含行为动词（睡觉/吃饭/工作） 
                    • 出现情绪形容词（累/烦/没意思）
                  
                  请根据最新对话内容生成严格符合以下结构的JSON："
                
                1. 使用以下数据结构：
                {
                  "out_question": "boolean",      // 根据场景判断，是否合理在下一轮问答中抛出问题
                  "out_question_id": "int",     // 若抛出问题，则提供问题内容的索引，若不抛出问题，则为-1
                  "out_question_content": "string",  // 若抛出问题，则提供问题内容，若不抛出问题，则为空字符串
                  
                  "get_score": "boolean",    // 上一轮含有问题（以输出为准）若需要获取得分，在进行分析后回答有效，
                                             // 若不能能够提供评分或者不需要获取得分，则返回返回false，否则返回true
                  "score": "int",     // 若get_score为true，则提供评分，否则返回-1
                  "score_id": "int"       // 若get_score为true，则提供本次评分的题目的索引，否则返回-1
                }
                2. 必须包含所有指定字段
                3. 保持JSON结构完整，无需Markdown代码块包裹
                4. 严格遵循数据类型要求
                
                
                示例输入：
                上一轮对话内容如下：
                助手：除了考试成绩带来的压力，你最近有没有觉得对日常活动失去兴趣？比如原本喜欢的运动、社交，甚至上课都很难提起劲？
                用户：其实……这学期我经常逃课在宿舍打游戏，明知道不该这样，但就是不想动。以前还挺喜欢打篮球的，现在连队友喊我都不想去。
                
                上一轮对话是否含有问题：是-题目2-做事时提不起劲或没有兴趣
                
                剩余的题目如下：
                
                3、你的睡眠情况如何？比如难以入睡、易醒或睡得过多？
                4、你是否经常感到疲劳或缺乏精力？
                7、你是否难以集中注意力，或者经常感到脑子一片空白？
                 
                示例输出：
                {
                  "out_question": True,      
                  "out_question_id": "7",     
                  "out_question_content": "你是否难以集中注意力，或者经常感到脑子一片空白？",  
                  
                  "get_score": True,    
                  "score": 0,     
                  "score_id": 2
                }
                
                ###########
                以下是用户输入：
            """

        self.questions = list()
        self.question = list()
        self.session_item = {
            'out_question': False,
            'out_question_id': -1,
            'out_question_content': "",
            'get_score': False,
            'score': -1,
            'score_id': -1
        }

        self.end_item_chunk = ["感谢", "你的参与", '测评', "已经结束"
                               "可以通过", "历史数据", "查看", "您的报告",
                               "[END]"]

        with open(column_path, 'r', encoding='utf-8') as f:
            column_item = json.load(f)

        self.questions = column_item['PHQ-9']["questions"]
        for item in self.questions:
            self.question.append([item['number'], item['question']])

    def buildResponse(self, message):
        response_stream = self.client.chat.completions.create(
            model='Qwen/Qwen2.5-7B-Instruct',
            messages=message,
            stream=True,
            temperature=0.7
        )

        for chunk in response_stream:
            content = chunk.choices[0].delta.content or ""
            if content:
                yield content
            if chunk.choices[0].finish_reason is not None:
                yield "[END]"
                break

    def backToQuestion(self):
        return self.session_item

    def buildResponsePHQ9(self, messages, log_question, submit_quesiton):

        lack_question = [
            [self.question[i][0] - 1, self.question[i][1]] for i in range(len(self.question))
            if log_question[i] == None
        ]

        if not lack_question:
            for chunk in self.end_item_chunk:
                content = chunk
                yield content
                if chunk == "[END]":
                    break
                else:
                    sleep(0.5)

        lack_question_prompt = "剩余的题目如下："

        for question in lack_question:
            lack_question_prompt += f"题目{question[0]}: {question[1]}\n"

        if submit_quesiton != -1:
            key = True
            for question in lack_question:
                if question[0] == submit_quesiton:
                    last_round_prompt = f"是-题目{submit_quesiton}-{question[1]}"
                    key = False
                    break
            if key:
                last_round_prompt = f"否"
        else:
            last_round_prompt = f"否"

        phq9_judge_prompt = self.phq9_judge_prompt + f"""
        
                        上一轮对话内容如下：
                        助手：{messages[-2]['content']}
                        用户：{messages[-1]['content']}
                        
                        上一轮对话是否含有问题：{last_round_prompt}
                        
                        {lack_question_prompt}
                """

        response = self.client.chat.completions.create(
            model="Pro/deepseek-ai/DeepSeek-V3",
            messages=[
                {
                    'role': "user",
                    'content': phq9_judge_prompt
                }
            ],
            temperature=0.3,
            max_tokens=8192,

            response_format={"type": "json_object"}
        )

        judge_response = json.loads(response.choices[0].message.content)
        with open(r'FerpaApp//tools//Log//logger.txt', 'a', encoding='utf-8') as file:
            file.write(f"\n")
            file.write(f"\n问题：{messages[-2]['content']}")
            file.write(f"\n回答：{messages[-1]['content']}")
            file.write(f"\n剩余问题{log_question},本轮提交问题{last_round_prompt}")
            file.write(f"\n剩余问题{lack_question_prompt}-本轮分析结果：{judge_response}")
        file.close()

        if judge_response['out_question']:
            self.session_item['out_question'] = True
            self.session_item['out_question_id'] = int(judge_response['out_question_id'])
            self.session_item['out_question_content'] = judge_response['out_question_content']
            messages[0]['content'] = (self.phq9_set_system + self.phq9_response_prompt[1] +
                                      judge_response['out_question_content'] +
                                      "\n用户上一轮的回答：" + messages[-1]['content'] +
                                      "结合以上内容，输出：")

        else:
            self.session_item['out_question'] = False
            self.session_item['out_question_id'] = -1
            self.session_item['out_question_content'] = ""
            messages[0]['content'] = self.phq9_set_system + self.phq9_response_prompt[0] + messages[-1]['content']

        if judge_response['get_score']:
            self.session_item['get_score'] = True
            self.session_item['score'] = int(judge_response['score'])
            self.session_item['score_id'] = int(judge_response['score_id'])
        else:
            self.session_item['get_score'] = False
            self.session_item['score'] = -1
            self.session_item['score_id'] = -1

        response_stream = self.client.chat.completions.create(
            model='Pro/deepseek-ai/DeepSeek-V3',
            messages=messages,
            stream=True,
            temperature=0.5,
            max_tokens=8192,
        )

        for chunk in response_stream:
            content = chunk.choices[0].delta.content or ""
            if content:
                yield content
            if chunk.choices[0].finish_reason is not None:
                yield "[END]"
                break
